<!doctype html><html lang="zh"><head><meta charset="utf-8"><meta name="generator" content="Hexo 4.2.1"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta><title>Java之线程池的成长之路 - Trainoo的博客</title><meta description="开发者,程序猿,编程,代码,开源,IT网站,Developer,Programmer,Coder"><meta property="og:type" content="blog"><meta property="og:title" content="Trainoo"><meta property="og:url" content="/"><meta property="og:site_name" content="Trainoo"><meta property="og:description" content="开发者,程序猿,编程,代码,开源,IT网站,Developer,Programmer,Coder"><meta property="og:locale" content="zh_CN"><meta property="og:image" content="/img/header.png"><meta property="article:published_time" content="2018-06-21T08:58:00.000Z"><meta property="article:modified_time" content="2021-04-12T09:29:16.918Z"><meta property="article:author" content="Trainoo"><meta property="article:tag" content="java"><meta property="article:tag" content="线程池"><meta property="article:tag" content="转载"><meta property="twitter:card" content="summary"><meta property="twitter:image" content="/img/header.png"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"/"},"headline":"Trainoo","image":["/img/header.png"],"datePublished":"2018-06-21T08:58:00.000Z","dateModified":"2021-04-12T09:29:16.918Z","author":{"@type":"Person","name":"Trainoo"},"description":"开发者,程序猿,编程,代码,开源,IT网站,Developer,Programmer,Coder"}</script><link rel="canonical" href="https://trainoo.gitee.io/2018/06/21/Java-thread-pool/"><link rel="alternative" href="/atom.xml" title="Trainoo的博客" type="application/atom+xml"><link rel="icon" href="/img/favicon.png"><link rel="stylesheet" href="/cdn/css/fontawesome.all.css"><link rel="stylesheet" href="/cdn/js/styles/atom-one-light.css"><link rel="stylesheet" href="/cdn/css/css2.css"><link rel="stylesheet" href="/css/default.css"><style>body>.footer,body>.navbar,body>.section{opacity:0}</style><script src="/cdn/js/pace.min.js"></script><script src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" defer></script><link rel="stylesheet" href="/cdn/js/dist/css/lightgallery.min.css"><link rel="stylesheet" href="/cdn/js/dist/css/justifiedGallery.min.css"></head><body class="is-2-column"><script type="text/javascript" src="/js/theme-night.js"></script><canvas id="universe"></canvas><nav class="navbar navbar-main"><div class="container"><div class="navbar-brand justify-content-center"><a class="navbar-item navbar-logo" href="/"><img class="navbar-logo-img" src="/img/logo.png" alt="Trainoo的博客" height="28"></a></div><div class="navbar-menu"><div class="navbar-start"><a class="navbar-item" href="/">首页</a><a class="navbar-item" href="/archives">时间轴</a><a class="navbar-item" href="/categories/%E7%9B%B8%E5%86%8C">相册</a><a class="navbar-item" href="/friend">友链</a><a class="navbar-item" href="/about">关于</a></div><div class="navbar-end"><a class="navbar-item" target="_blank" rel="noopener" title="Download on GitHub" href="https://github.com/trainoozhou"><i class="fab fa-github"></i></a><a class="navbar-item search" title="搜索" href="javascript:;"><i class="fas fa-search"></i></a><a class="navbar-item" id="night-nav" title="Night Mode" href="javascript:;"><i class="fas fa-moon" id="night-icon"></i></a></div></div></div></nav><section class="section"><div class="container"><div class="columns"><div class="column order-2 column-main is-8-tablet is-8-desktop is-8-widescreen"><div class="card"><div class="card-image"><span class="image is-7by3"><img class="thumbnail" src="/picture/2018/20180621001.png" alt="Java之线程池的成长之路"></span></div><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><time class="level-item" datetime="2018-06-21T08:58:00.000Z" title="2018-06-21T08:58:00.000Z">2018-06-21</time><span class="level-item"><a class="link-muted" href="/categories/%E5%AD%A6%E4%B9%A0/">学习</a><span> / </span><a class="link-muted" href="/categories/%E5%AD%A6%E4%B9%A0/java/">java</a></span><span class="level-item" id="busuanzi_container_page_pv"><i class="far fa-eye"></i>&nbsp;&nbsp;<span id="busuanzi_value_page_pv">0</span>次访问</span></div></div><h1 class="title is-3 is-size-4-mobile">Java之线程池的成长之路</h1><div class="content"><blockquote><p>本文转载自公众号： 猿天地</p></blockquote><h4 id="1、背景"><a href="#1、背景" class="headerlink" title="1、背景"></a>1、背景</h4><p>相信大家在面试过程中遇到面试官问线程的很多，线程过后就是线程池了。从易到难，都是这么个过程，还有就是确实很多人在工作中接触线程池比较少，最多的也就是创建一个然后往里面提交线程，对于一些经验很丰富的面试官来说，一下就可以问出很多线程池相关的问题，与其被问的晕头转向，还不如好好学习。</p><p>此时不努力更待何时。</p><a id="more"></a><h5 id="2、什么是线程池？"><a href="#2、什么是线程池？" class="headerlink" title="2、什么是线程池？"></a>2、什么是线程池？</h5><p>线程池是一种多线程处理形式，处理过程中将任务提交到线程池，任务的执行交由线程池来管理。</p><p>如果每个请求都创建一个线程去处理，那么服务器的资源很快就会被耗尽，使用线程池可以减少创建和销毁线程的次数，每个工作线程都可以被重复利用，可执行多个任务。</p><p>如果用生活中的列子来说明，我们可以把线程池当做一个客服团队，如果同时有1000个人打电话进行咨询，按照正常的逻辑那就是需要1000个客服接听电话，服务客户。</p><p>现实往往需要考虑到很多层面的东西，比如：资源够不够，招这么多人需要费用比较多。正常的做法就是招100个人成立一个客服中心，当有电话进来后分配没有接听的客服进行服务，如果超出了100个人同时咨询的话，提示客户等待，稍后处理，等有客服空出来就可以继续服务下一个客户，这样才能达到一个资源的合理利用，实现效益的最大化。</p><h5 id="3、Java中的线程池种类"><a href="#3、Java中的线程池种类" class="headerlink" title="3、Java中的线程池种类"></a>3、Java中的线程池种类</h5><ul><li>newSingleThreadExecutor</li></ul><p>创建方式：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ExecutorService pool &#x3D; Executors.newSingleThreadExecutor();</span><br></pre></td></tr></table></figure><p>一个单线程的线程池。这个线程池只有一个线程在工作，也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束，那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。</p><p>使用方式：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">import java.util.concurrent.ExecutorService; </span><br><span class="line">import java.util.concurrent.Executors; </span><br><span class="line">public class ThreadPool &#123; </span><br><span class="line">    public static void main(String[] args) &#123; </span><br><span class="line">        ExecutorService pool &#x3D; Executors.newSingleThreadExecutor(); </span><br><span class="line">        for (int i &#x3D; 0; i &lt; 10; i++) &#123; </span><br><span class="line">            pool.execute(() -&gt; &#123; </span><br><span class="line">                System.out.println(Thread.currentThread().getName() + &quot;\t开始发车啦....&quot;); </span><br><span class="line">            &#125;); </span><br><span class="line">        &#125; </span><br><span class="line">    &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>输出结果如下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-1    开始发车啦....</span><br></pre></td></tr></table></figure><p>从输出的结果我们可以看出，一直只有一个线程在运行。</p><ul><li>newFixedThreadPool</li></ul><p>创建方式：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ExecutorService pool &#x3D; Executors.newFixedThreadPool(10);</span><br></pre></td></tr></table></figure><p>创建固定大小的线程池。每次提交一个任务就创建一个线程，直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变，如果某个线程因为执行异常而结束，那么线程池会补充一个新线程。</p><p>使用方式：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">import java.util.concurrent.ExecutorService;</span><br><span class="line">import java.util.concurrent.Executors;</span><br><span class="line">public class ThreadPool &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        ExecutorService pool &#x3D; Executors.newFixedThreadPool(10);</span><br><span class="line">        for (int i &#x3D; 0; i &lt; 10; i++) &#123;</span><br><span class="line">            pool.execute(() -&gt; &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + &quot;\t开始发车啦....&quot;);</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>输出结果如下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">pool-1-thread-1    开始发车啦....</span><br><span class="line">pool-1-thread-4    开始发车啦....</span><br><span class="line">pool-1-thread-3    开始发车啦....</span><br><span class="line">pool-1-thread-2    开始发车啦....</span><br><span class="line">pool-1-thread-6    开始发车啦....</span><br><span class="line">pool-1-thread-7    开始发车啦....</span><br><span class="line">pool-1-thread-5    开始发车啦....</span><br><span class="line">pool-1-thread-8	   开始发车啦....</span><br><span class="line">pool-1-thread-9	   开始发车啦....</span><br><span class="line">pool-1-thread-10   开始发车啦....</span><br></pre></td></tr></table></figure><ul><li>newCachedThreadPool</li></ul><p>创建方式：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ExecutorService pool &#x3D; Executors.newCachedThreadPool();</span><br></pre></td></tr></table></figure><p>创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程，那么就会回收部分空闲的线程，当任务数增加时，此线程池又添加新线程来处理任务。</p><p>使用方式如上2所示。</p><ul><li>newScheduledThreadPool</li></ul><p>创建方式：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ScheduledExecutorService pool &#x3D; Executors.newScheduledThreadPool(10);</span><br></pre></td></tr></table></figure><p>此线程池支持定时以及周期性执行任务的需求。</p><p>使用方式：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">import java.util.concurrent.Executors;</span><br><span class="line">import java.util.concurrent.ScheduledExecutorService;</span><br><span class="line">import java.util.concurrent.TimeUnit;</span><br><span class="line">public class ThreadPool &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        ScheduledExecutorService pool &#x3D; Executors.newScheduledThreadPool(10);</span><br><span class="line">        for (int i &#x3D; 0; i &lt; 10; i++) &#123;</span><br><span class="line">            pool.schedule(() -&gt; &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + &quot;\t开始发车啦....&quot;);</span><br><span class="line">            &#125;, 10, TimeUnit.SECONDS);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面演示的是延迟10秒执行任务,如果想要执行周期性的任务可以用下面的方式，每秒执行一次。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;&#x2F;pool.scheduleWithFixedDelay也可以</span><br><span class="line">pool.scheduleAtFixedRate(() -&gt; &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + &quot;\t开始发车啦....&quot;);</span><br><span class="line">&#125;, 1, 1, TimeUnit.SECONDS);</span><br></pre></td></tr></table></figure><ul><li>newWorkStealingPool</li></ul><p>newWorkStealingPool是jdk1.8才有的，会根据所需的并行层次来动态创建和关闭线程，通过使用多个队列减少竞争，底层用的ForkJoinPool来实现的。ForkJoinPool的优势在于，可以充分利用多cpu，多核cpu的优势，把一个任务拆分成多个“小任务”，把多个“小任务”放到多个处理器核心上并行执行；当多个“小任务”执行完成之后，再将这些执行结果合并起来即可。</p><h5 id="4、说说线程池的拒绝策略"><a href="#4、说说线程池的拒绝策略" class="headerlink" title="4、说说线程池的拒绝策略"></a>4、说说线程池的拒绝策略</h5><p>当请求任务不断的过来，而系统此时又处理不过来的时候，我们需要采取的策略是拒绝服务。RejectedExecutionHandler接口提供了拒绝任务处理的自定义方法的机会。在ThreadPoolExecutor中已经包含四种处理策略。</p><ul><li><p>AbortPolicy策略：该策略会直接抛出异常，阻止系统正常工作。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public static class AbortPolicy implements RejectedExecutionHandler &#123;</span><br><span class="line">    public AbortPolicy() &#123; &#125;</span><br><span class="line">    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) &#123;</span><br><span class="line">        throw new RejectedExecutionException(&quot;Task &quot; + r.toString() +</span><br><span class="line">                                                 &quot; rejected from &quot; +</span><br><span class="line">                                                 e.toString());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>CallerRunsPolicy 策略：只要线程池未关闭，该策略直接在调用者线程中，运行当前的被丢弃的任务。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public static class CallerRunsPolicy implements RejectedExecutionHandler &#123;</span><br><span class="line">    public CallerRunsPolicy() &#123; &#125;</span><br><span class="line">    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) &#123;</span><br><span class="line">        if (!e.isShutdown()) &#123;</span><br><span class="line">                r.run();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>DiscardOleddestPolicy策略： 该策略将丢弃最老的一个请求，也就是即将被执行的任务，并尝试再次提交当前任务。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">public static class DiscardOldestPolicy implements RejectedExecutionHandler &#123;</span><br><span class="line">    public DiscardOldestPolicy() &#123; &#125;</span><br><span class="line">    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) &#123;</span><br><span class="line">        if (!e.isShutdown()) &#123;</span><br><span class="line">            e.getQueue().poll();</span><br><span class="line">            e.execute(r);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>DiscardPolicy策略：该策略默默的丢弃无法处理的任务，不予任何处理。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">public static class DiscardPolicy implements RejectedExecutionHandler &#123;</span><br><span class="line">    public DiscardPolicy() &#123; &#125;</span><br><span class="line">    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><p>除了JDK默认为什么提供的四种拒绝策略，我们可以根据自己的业务需求去自定义拒绝策略，自定义的方式很简单，直接实现RejectedExecutionHandler接口即可。</p><p>比如Spring integration中就有一个自定义的拒绝策略CallerBlocksPolicy，将任务插入到队列中，直到队列中有空闲并插入成功的时候，否则将根据最大等待时间一直阻塞，直到超时。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">package org.springframework.integration.util;</span><br><span class="line">import java.util.concurrent.BlockingQueue;</span><br><span class="line">import java.util.concurrent.RejectedExecutionException;</span><br><span class="line">import java.util.concurrent.RejectedExecutionHandler;</span><br><span class="line">import java.util.concurrent.ThreadPoolExecutor;</span><br><span class="line">import java.util.concurrent.TimeUnit;</span><br><span class="line">import org.apache.commons.logging.Log;</span><br><span class="line">import org.apache.commons.logging.LogFactory;</span><br><span class="line">public class CallerBlocksPolicy implements RejectedExecutionHandler &#123;</span><br><span class="line">    private static final Log logger &#x3D; LogFactory.getLog(CallerBlocksPolicy.class);</span><br><span class="line">    private final long maxWait;</span><br><span class="line">    &#x2F;**</span><br><span class="line">     * @param maxWait The maximum time to wait for a queue slot to be</span><br><span class="line">     * available, in milliseconds.</span><br><span class="line">     *&#x2F;</span><br><span class="line">    public CallerBlocksPolicy(long maxWait) &#123;</span><br><span class="line">        this.maxWait &#x3D; maxWait;</span><br><span class="line">    &#125;</span><br><span class="line">    @Override</span><br><span class="line">    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) &#123;</span><br><span class="line">        if (!executor.isShutdown()) &#123;</span><br><span class="line">            try &#123;</span><br><span class="line">                BlockingQueue&lt;Runnable&gt; queue &#x3D; executor.getQueue();</span><br><span class="line">                if (logger.isDebugEnabled()) &#123;</span><br><span class="line">                    logger.debug(&quot;Attempting to queue task execution for &quot; + this.maxWait + &quot; milliseconds&quot;);</span><br><span class="line">                &#125;</span><br><span class="line">                if (!queue.offer(r, this.maxWait, TimeUnit.MILLISECONDS)) &#123;</span><br><span class="line">                    throw new RejectedExecutionException(&quot;Max wait time expired to queue task&quot;);</span><br><span class="line">                &#125;</span><br><span class="line">                if (logger.isDebugEnabled()) &#123;</span><br><span class="line">                    logger.debug(&quot;Task execution queued&quot;);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            catch (InterruptedException e) &#123;</span><br><span class="line">                Thread.currentThread().interrupt();</span><br><span class="line">                throw new RejectedExecutionException(&quot;Interrupted&quot;, e);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        else &#123;</span><br><span class="line">            throw new RejectedExecutionException(&quot;Executor has been shut down&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>定义好之后如何使用呢？光定义没用的呀，一定要用到线程池中呀，可以通过下面的方式自定义线程池，指定拒绝策略。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">BlockingQueue&lt;Runnable&gt; workQueue &#x3D; new ArrayBlockingQueue&lt;&gt;(100);</span><br><span class="line">ThreadPoolExecutor executor &#x3D; new ThreadPoolExecutor(</span><br><span class="line">    10, 100, 10, TimeUnit.SECONDS, workQueue, new CallerBlocksPolicy());</span><br></pre></td></tr></table></figure><h5 id="5、execute和submit的区别？"><a href="#5、execute和submit的区别？" class="headerlink" title="5、execute和submit的区别？"></a>5、execute和submit的区别？</h5><p>在前面的讲解中，我们执行任务是用的execute方法，除了execute方法，还有一个submit方法也可以执行我们提交的任务。</p><p>这两个方法有什么区别呢？分别适用于在什么场景下呢？我们来做一个简单的分析。</p><p>execute适用于不需要关注返回值的场景，只需要将线程丢到线程池中去执行就可以了。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public class ThreadPool &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        ExecutorService pool &#x3D; Executors.newFixedThreadPool(10);</span><br><span class="line">        pool.execute(() -&gt; &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + &quot;\t开始发车啦....&quot;);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>submit方法适用于需要关注返回值的场景，submit方法的定义如下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">public interface ExecutorService extends Executor &#123;</span><br><span class="line">　　...</span><br><span class="line">　　&lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task);</span><br><span class="line">　　&lt;T&gt; Future&lt;T&gt; submit(Runnable task, T result);</span><br><span class="line">　　Future&lt;?&gt; submit(Runnable task);</span><br><span class="line">　　...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>其子类AbstractExecutorService实现了submit方法,可以看到无论参数是Callable还是Runnable，最终都会被封装成RunnableFuture，然后再调用execute执行。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * @throws RejectedExecutionException &#123;@inheritDoc&#125;</span><br><span class="line"> * @throws NullPointerException       &#123;@inheritDoc&#125;</span><br><span class="line"> *&#x2F;</span><br><span class="line">public Future&lt;?&gt; submit(Runnable task) &#123;</span><br><span class="line">    if (task &#x3D;&#x3D; null) throw new NullPointerException();</span><br><span class="line">    RunnableFuture&lt;Void&gt; ftask &#x3D; newTaskFor(task, null);</span><br><span class="line">    execute(ftask);</span><br><span class="line">    return ftask;</span><br><span class="line">&#125;</span><br><span class="line">&#x2F;**</span><br><span class="line"> * @throws RejectedExecutionException &#123;@inheritDoc&#125;</span><br><span class="line"> * @throws NullPointerException       &#123;@inheritDoc&#125;</span><br><span class="line"> *&#x2F;</span><br><span class="line">public &lt;T&gt; Future&lt;T&gt; submit(Runnable task, T result) &#123;</span><br><span class="line">    if (task &#x3D;&#x3D; null) throw new NullPointerException();</span><br><span class="line">    RunnableFuture&lt;T&gt; ftask &#x3D; newTaskFor(task, result);</span><br><span class="line">    execute(ftask);</span><br><span class="line">    return ftask;</span><br><span class="line">&#125;</span><br><span class="line">&#x2F;**</span><br><span class="line"> * @throws RejectedExecutionException &#123;@inheritDoc&#125;</span><br><span class="line"> * @throws NullPointerException       &#123;@inheritDoc&#125;</span><br><span class="line"> *&#x2F;</span><br><span class="line">public &lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task) &#123;</span><br><span class="line">    if (task &#x3D;&#x3D; null) throw new NullPointerException();</span><br><span class="line">    RunnableFuture&lt;T&gt; ftask &#x3D; newTaskFor(task);</span><br><span class="line">    execute(ftask);</span><br><span class="line">    return ftask;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>下面我们来看看这三个方法分别如何去使用：</p><p>submit(Callable task);</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">public class ThreadPool &#123;</span><br><span class="line">    public static void main(String[] args) throws Exception &#123;</span><br><span class="line">        ExecutorService pool &#x3D; Executors.newFixedThreadPool(10);</span><br><span class="line">        Future&lt;String&gt; future &#x3D; pool.submit(new Callable&lt;String&gt;() &#123;</span><br><span class="line">            @Override</span><br><span class="line">            public String call() throws Exception &#123;</span><br><span class="line">                return &quot;Hello&quot;;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        String result &#x3D; future.get();</span><br><span class="line">        System.out.println(result);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>submit(Runnable task, T result);</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">public class ThreadPool &#123;</span><br><span class="line">    public static void main(String[] args) throws Exception &#123;</span><br><span class="line">        ExecutorService pool &#x3D; Executors.newFixedThreadPool(10);</span><br><span class="line">        Data data &#x3D; new Data();</span><br><span class="line">        Future&lt;Data&gt; future &#x3D; pool.submit(new MyRunnable(data), data);</span><br><span class="line">        String result &#x3D; future.get().getName();</span><br><span class="line">        System.out.println(result);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">class Data &#123;</span><br><span class="line">    String name;</span><br><span class="line">    public String getName() &#123;</span><br><span class="line">        return name;</span><br><span class="line">    &#125;</span><br><span class="line">    public void setName(String name) &#123;</span><br><span class="line">        this.name &#x3D; name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">class MyRunnable implements Runnable &#123;</span><br><span class="line">    private Data data;</span><br><span class="line">    public MyRunnable(Data data) &#123;</span><br><span class="line">        this.data &#x3D; data;</span><br><span class="line">    &#125;</span><br><span class="line">    @Override</span><br><span class="line">    public void run() &#123;</span><br><span class="line">        data.setName(&quot;yinjihuan&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Future submit(Runnable task);</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">直接submit一个Runnable是拿不到返回值的，返回值就是null.</span><br></pre></td></tr></table></figure><h5 id="6、五种线程池的使用场景"><a href="#6、五种线程池的使用场景" class="headerlink" title="6、五种线程池的使用场景"></a>6、五种线程池的使用场景</h5><ul><li>newSingleThreadExecutor：一个单线程的线程池，可以用于需要保证顺序执行的场景，并且只有一个线程在执行。</li><li>newFixedThreadPool：一个固定大小的线程池，可以用于已知并发压力的情况下，对线程数做限制。</li><li>newCachedThreadPool：一个可以无限扩大的线程池，比较适合处理执行时间比较小的任务。</li><li>newScheduledThreadPool：可以延时启动，定时启动的线程池，适用于需要多个后台线程执行周期任务的场景。</li><li>newWorkStealingPool：一个拥有多个任务队列的线程池，可以减少连接数，创建当前可用cpu数量的线程来并行执行。</li></ul><h5 id="7、线程池的关闭"><a href="#7、线程池的关闭" class="headerlink" title="7、线程池的关闭"></a>7、线程池的关闭</h5><p>关闭线程池可以调用shutdownNow和shutdown两个方法来实现</p><p>shutdownNow：对正在执行的任务全部发出interrupt()，停止执行，对还未开始执行的任务全部取消，并且返回还没开始的任务列表。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">public class ThreadPool &#123;</span><br><span class="line">    public static void main(String[] args) throws Exception &#123;</span><br><span class="line">        ExecutorService pool &#x3D; Executors.newFixedThreadPool(1);</span><br><span class="line">        for (int i &#x3D; 0; i &lt; 5; i++) &#123;</span><br><span class="line">            System.err.println(i);</span><br><span class="line">            pool.execute(() -&gt; &#123;</span><br><span class="line">                try &#123;</span><br><span class="line">                    Thread.sleep(30000);</span><br><span class="line">                    System.out.println(&quot;--&quot;);</span><br><span class="line">                &#125; catch (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        Thread.sleep(1000);</span><br><span class="line">        List&lt;Runnable&gt; runs &#x3D; pool.shutdownNow();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面的代码模拟了立即取消的场景，往线程池里添加5个线程任务，然后sleep一段时间，线程池只有一个线程，如果此时调用shutdownNow后应该需要中断一个正在执行的任务和返回4个还未执行的任务，控制台输出下面的内容：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">0</span><br><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">[fs.ThreadPool$$Lambda$1&#x2F;990368553@682a0b20, </span><br><span class="line">fs.ThreadPool$$Lambda$1&#x2F;990368553@682a0b20, </span><br><span class="line">fs.ThreadPool$$Lambda$1&#x2F;990368553@682a0b20, </span><br><span class="line">fs.ThreadPool$$Lambda$1&#x2F;990368553@682a0b20]</span><br><span class="line">java.lang.InterruptedException: sleep interrupted</span><br><span class="line">    at java.lang.Thread.sleep(Native Method)</span><br><span class="line">    at fs.ThreadPool.lambda$0(ThreadPool.java:15)</span><br><span class="line">    at fs.ThreadPool$$Lambda$1&#x2F;990368553.run(Unknown Source)</span><br><span class="line">    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)</span><br><span class="line">    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)</span><br><span class="line">    at java.lang.Thread.run(Thread.java:745)</span><br></pre></td></tr></table></figure><p>shutdown：当我们调用shutdown后，线程池将不再接受新的任务，但也不会去强制终止已经提交或者正在执行中的任务。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">public class ThreadPool &#123;</span><br><span class="line">    public static void main(String[] args) throws Exception &#123;</span><br><span class="line">        ExecutorService pool &#x3D; Executors.newFixedThreadPool(1);</span><br><span class="line">        for (int i &#x3D; 0; i &lt; 5; i++) &#123;</span><br><span class="line">            System.err.println(i);</span><br><span class="line">            pool.execute(() -&gt; &#123;</span><br><span class="line">                try &#123;</span><br><span class="line">                    Thread.sleep(30000);</span><br><span class="line">                    System.out.println(&quot;--&quot;);</span><br><span class="line">                &#125; catch (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        Thread.sleep(1000);</span><br><span class="line">        pool.shutdown();</span><br><span class="line">        pool.execute(() -&gt; &#123;</span><br><span class="line">            try &#123;</span><br><span class="line">                Thread.sleep(30000);</span><br><span class="line">                System.out.println(&quot;--&quot;);</span><br><span class="line">            &#125; catch (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面的代码模拟了正在运行的状态，然后调用shutdown，接着再往里面添加任务，肯定是拒绝添加的，请看输出结果：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">0</span><br><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">Exception in thread &quot;main&quot; java.util.concurrent.RejectedExecutionException: Task fs.ThreadPool$$Lambda$2&#x2F;1747585824@3d075dc0 rejected from java.util.concurrent.ThreadPoolExecutor@214c265e[Shutting down, pool size &#x3D; 1, active threads &#x3D; 1, queued tasks &#x3D; 4, completed tasks &#x3D; 0]</span><br><span class="line">    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)</span><br><span class="line">    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)</span><br><span class="line">    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)</span><br><span class="line">    at fs.ThreadPool.main(ThreadPool.java:24)</span><br></pre></td></tr></table></figure><p>还有一些业务场景下需要知道线程池中的任务是否全部执行完成，当我们关闭线程池之后，可以用isTerminated来判断所有的线程是否执行完成，千万不要用isShutdown，isShutdown只是返回你是否调用过shutdown的结果。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">public class ThreadPool &#123;</span><br><span class="line">    public static void main(String[] args) throws Exception &#123;</span><br><span class="line">        ExecutorService pool &#x3D; Executors.newFixedThreadPool(1);</span><br><span class="line">        for (int i &#x3D; 0; i &lt; 5; i++) &#123;</span><br><span class="line">            System.err.println(i);</span><br><span class="line">            pool.execute(() -&gt; &#123;</span><br><span class="line">                try &#123;</span><br><span class="line">                    Thread.sleep(3000);</span><br><span class="line">                    System.out.println(&quot;--&quot;);</span><br><span class="line">                &#125; catch (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        Thread.sleep(1000);</span><br><span class="line">        pool.shutdown();</span><br><span class="line">        while(true)&#123;  </span><br><span class="line">            if(pool.isTerminated())&#123;  </span><br><span class="line">                System.out.println(&quot;所有的子线程都结束了！&quot;);  </span><br><span class="line">                break;  </span><br><span class="line">            &#125;  </span><br><span class="line">            Thread.sleep(1000);    </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="8、自定义线程池"><a href="#8、自定义线程池" class="headerlink" title="8、自定义线程池"></a>8、自定义线程池</h5><p>在实际的使用过程中，大部分我们都是用Executors去创建线程池直接使用，如果有一些其他的需求，比如指定线程池的拒绝策略，阻塞队列的类型，线程名称的前缀等等，我们可以采用自定义线程池的方式来解决。</p><p>如果只是简单的想要改变线程名称的前缀的话可以自定义ThreadFactory来实现，在Executors.new…中有一个ThreadFactory的参数，如果没有指定则用的是DefaultThreadFactory。</p><p>自定义线程池核心在于创建一个ThreadPoolExecutor对象，指定参数<br>下面我们看下ThreadPoolExecutor构造函数的定义：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">public ThreadPoolExecutor(int corePoolSize,</span><br><span class="line">                              int maximumPoolSize,</span><br><span class="line">                              long keepAliveTime,</span><br><span class="line">                              TimeUnit unit,</span><br><span class="line">                              BlockingQueue&lt;Runnable&gt; workQueue,</span><br><span class="line">                              ThreadFactory threadFactory,</span><br><span class="line">                              RejectedExecutionHandler handler) ;</span><br></pre></td></tr></table></figure><ul><li><p>corePoolSize<br>线程池大小，决定着新提交的任务是新开线程去执行还是放到任务队列中，也是线程池的最最核心的参数。一般线程池开始时是没有线程的，只有当任务来了并且线程数量小于corePoolSize才会创建线程。</p></li><li><p>maximumPoolSize<br>最大线程数，线程池能创建的最大线程数量。</p></li><li><p>keepAliveTime<br>在线程数量超过corePoolSize后，多余空闲线程的最大存活时间。</p></li><li><p>unit<br>时间单位</p></li><li><p>workQueue<br>存放来不及处理的任务的队列，是一个BlockingQueue。</p></li><li><p>threadFactory<br>生产线程的工厂类，可以定义线程名，优先级等。</p></li><li><p>handler<br>拒绝策略，当任务来不及处理的时候，如何处理, 前面有讲解。</p></li></ul><p>了解上面的参数信息后我们就可以定义自己的线程池了，我这边用ArrayBlockingQueue替换了LinkedBlockingQueue，指定了队列的大小，当任务超出队列大小之后使用CallerRunsPolicy拒绝策略处理。</p><p>这样做的好处是严格控制了队列的大小，不会出现一直往里面添加任务的情况，有的时候任务处理的比较慢，任务数量过多会占用大量内存，导致内存溢出。</p><p>当然你也可以在提交到线程池的入口进行控制，比如用CountDownLatch, Semaphore等。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;**</span><br><span class="line"> * 自定义线程池&lt;br&gt;</span><br><span class="line"> * 默认的newFixedThreadPool里的LinkedBlockingQueue是一个无边界队列，如果不断的往里加任务，最终会导致内存的不可控&lt;br&gt;</span><br><span class="line"> * 增加了有边界的队列，使用了CallerRunsPolicy拒绝策略</span><br><span class="line"> * @author yinjihuan</span><br><span class="line"> *</span><br><span class="line"> *&#x2F;</span><br><span class="line">public class FangjiaThreadPoolExecutor &#123;</span><br><span class="line">    private static ExecutorService executorService &#x3D; newFixedThreadPool(50);</span><br><span class="line">    private static ExecutorService newFixedThreadPool(int nThreads) &#123;</span><br><span class="line">        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,</span><br><span class="line">                new ArrayBlockingQueue&lt;Runnable&gt;(10000), new DefaultThreadFactory(), new CallerRunsPolicy());</span><br><span class="line">    &#125;</span><br><span class="line">    public static void execute(Runnable command) &#123;</span><br><span class="line">        executorService.execute(command);</span><br><span class="line">    &#125;</span><br><span class="line">    public static void shutdown() &#123;</span><br><span class="line">        executorService.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">    static class DefaultThreadFactory implements ThreadFactory &#123;</span><br><span class="line">        private static final AtomicInteger poolNumber &#x3D; new AtomicInteger(1);</span><br><span class="line">        private final ThreadGroup group;</span><br><span class="line">        private final AtomicInteger threadNumber &#x3D; new AtomicInteger(1);</span><br><span class="line">        private final String namePrefix;</span><br><span class="line">        DefaultThreadFactory() &#123;</span><br><span class="line">            SecurityManager s &#x3D; System.getSecurityManager();</span><br><span class="line">            group &#x3D; (s !&#x3D; null) ? s.getThreadGroup() :</span><br><span class="line">                                  Thread.currentThread().getThreadGroup();</span><br><span class="line">            namePrefix &#x3D; &quot;FSH-pool-&quot; +</span><br><span class="line">                          poolNumber.getAndIncrement() +</span><br><span class="line">                         &quot;-thread-&quot;;</span><br><span class="line">        &#125;</span><br><span class="line">        public Thread newThread(Runnable r) &#123;</span><br><span class="line">            Thread t &#x3D; new Thread(group, r,</span><br><span class="line">                                  namePrefix + threadNumber.getAndIncrement(),</span><br><span class="line">                                  0);</span><br><span class="line">            if (t.isDaemon())</span><br><span class="line">                t.setDaemon(false);</span><br><span class="line">            if (t.getPriority() !&#x3D; Thread.NORM_PRIORITY)</span><br><span class="line">                t.setPriority(Thread.NORM_PRIORITY);</span><br><span class="line">            return t;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="END"><a href="#END" class="headerlink" title="END"></a>END</h5></div><div class="article-tags size-small is-uppercase mb-4"><span class="mr-2">#</span><a class="link-muted mr-2" rel="tag" href="/tags/java/">java</a><a class="link-muted mr-2" rel="tag" href="/tags/%E7%BA%BF%E7%A8%8B%E6%B1%A0/">线程池</a><a class="link-muted mr-2" rel="tag" href="/tags/%E8%BD%AC%E8%BD%BD/">转载</a></div><link rel="stylesheet" href="/cdn/js/dist/css/share.min.css"><div class="social-share"></div><script src="/cdn/js/dist/js/social-share.min.js"></script><script>window.onload=function(){var o=window.document.location.href,t=window.document.location.pathname;"/memory/"===t&&(document.getElementsByClassName("navbar-logo-img")[0].src="/img/logo-pink.png",document.getElementsByClassName("footer-logo-img")[0].src="/img/logo-pink.png"),o&&$("#artTitle").html()&&(t=o.indexOf(t),o=o.substring(0,t),t=$("#artTitle").html().substring(25),$("#artTitle").html(o+"/"+t))}</script></article></div><div class="card"><div class="card-content"><h3 class="menu-label has-text-centered">喜欢这篇文章？打赏一下作者吧</h3><div class="buttons is-centered"><a class="button is-info donate"><span class="icon is-small"><i class="fab fa-alipay"></i></span><span>支付宝</span><span class="qrcode"><img src="/img/alipay.png" alt="支付宝"></span></a><a class="button is-success donate"><span class="icon is-small"><i class="fab fa-weixin"></i></span><span>微信</span><span class="qrcode"><img src="/img/wechatpay.png" alt="微信"></span></a></div></div></div><nav class="post-navigation mt-4 level is-mobile"><div class="level-start"><a class="article-nav-prev level level-item link-muted" href="/2018/06/23/how-to-search-log-in-linux/"><i class="level-item fas fa-chevron-left"></i><span class="level-item">如何在Linux下优雅的查询日志</span></a></div><div class="level-end"><a class="article-nav-next level level-item link-muted" href="/2018/06/17/Python-tkinter-pracetice/"><span class="level-item">Python图形化界面Tkinter(十)-实战应用</span><i class="level-item fas fa-chevron-right"></i></a></div></nav></div><div class="column column-right is-4-tablet is-4-desktop is-4-widescreen order-3"><div class="card widget"><div class="card-content"><nav class="level"><div class="level-item has-text-centered flex-shrink-1"><div><figure class="image is-128x128 mx-auto mb-2"><img src="/img/header.png" alt="Trainoo"></figure><p class="title is-size-4 is-block line-height-inherit">Trainoo</p><p class="is-size-6 is-block">A simple man living a simple life</p><p class="is-size-6 is-flex justify-content-center"><i class="fas fa-map-marker-alt mr-1"></i><span>Earth, Solar System</span></p></div></div></nav><nav class="level is-mobile"><div class="level-item has-text-centered is-marginless"><div><p class="heading">文章</p><a href="/archives"><p class="title">55</p></a></div></div><div class="level-item has-text-centered is-marginless"><div><p class="heading">分类</p><a href="/categories"><p class="title">12</p></a></div></div><div class="level-item has-text-centered is-marginless"><div><p class="heading">标签</p><a href="/tags"><p class="title">36</p></a></div></div></nav><div class="level"><a class="level-item button is-primary is-rounded" href="https://space.bilibili.com/19555359/bangumi" target="_blank" rel="noopener">米娜桑，一起来追番吧</a></div><div class="level is-mobile"><a class="level-item button is-transparent is-marginless" target="_blank" rel="noopener" title="Github" href="https://github.com/trainoozhou"><i class="fab fa-github"></i></a><a class="level-item button is-transparent is-marginless" target="_blank" rel="noopener" title="Facebook" href="https://facebook.com"><i class="fab fa-facebook"></i></a><a class="level-item button is-transparent is-marginless" target="_blank" rel="noopener" title="Twitter" href="https://twitter.com"><i class="fab fa-twitter"></i></a><a class="level-item button is-transparent is-marginless" target="_blank" rel="noopener" title="Dribbble" href="mailto:trainoo@163.com"><i class="fab fa-dribbble"></i></a><a class="level-item button is-transparent is-marginless" target="_blank" rel="noopener" title="RSS" href="/"><i class="fas fa-rss"></i></a></div></div></div><div class="card widget"><link href="/music/APlayer.min.css"><div id="aplayer" style="margin:0 auto"></div><script src="/music/APlayer.min.js"></script><script src="/music/APlayer_Music.js"></script></div><div class="card widget"><div class="card-content"><h3 class="menu-label">最新文章</h3><article class="media"><a class="media-left" href="/2021/04/19/bokugashinootoomotanowa/"><p class="image is-64x64"><img class="thumbnail" src="/picture/2021/20210419001.jpg" alt="仆が死のうと思ったのは — 中島美嘉"></p></a><div class="media-content size-small"><p><time datetime="2021-04-19T04:00:00.000Z">2021-04-19</time></p><p class="title is-6"><a class="link-muted" href="/2021/04/19/bokugashinootoomotanowa/">仆が死のうと思ったのは — 中島美嘉</a></p><p class="is-uppercase"><a class="link-muted" href="/categories/%E9%BB%98%E8%AE%A4/">默认</a></p></div></article><article class="media"><a class="media-left" href="/2021/04/09/ribbon-retry-problem/"><p class="image is-64x64"><img class="thumbnail" src="/picture/2021/20210409001.jpg" alt="记一次Ribbon重试配置不生效问题"></p></a><div class="media-content size-small"><p><time datetime="2021-04-09T12:30:00.000Z">2021-04-09</time></p><p class="title is-6"><a class="link-muted" href="/2021/04/09/ribbon-retry-problem/">记一次Ribbon重试配置不生效问题</a></p><p class="is-uppercase"><a class="link-muted" href="/categories/%E5%AD%A6%E4%B9%A0/">学习</a> / <a class="link-muted" href="/categories/%E5%AD%A6%E4%B9%A0/%E9%97%AE%E9%A2%98%E5%A4%84%E7%90%86/">问题处理</a></p></div></article><article class="media"><a class="media-left" href="/2021/04/07/novel-zhuixu/"><p class="image is-64x64"><img class="thumbnail" src="/picture/2021/20210407001.jpg" alt="《赘婿》摘录"></p></a><div class="media-content size-small"><p><time datetime="2021-04-06T16:00:00.000Z">2021-04-07</time></p><p class="title is-6"><a class="link-muted" href="/2021/04/07/novel-zhuixu/">《赘婿》摘录</a></p><p class="is-uppercase"><a class="link-muted" href="/categories/%E9%BB%98%E8%AE%A4/">默认</a></p></div></article><article class="media"><a class="media-left" href="/2020/05/31/blog-theme-upgrade/"><p class="image is-64x64"><img class="thumbnail" src="/picture/2020/20200531001.png" alt="记Icarus博客主题升级"></p></a><div class="media-content size-small"><p><time datetime="2020-05-31T03:30:00.000Z">2020-05-31</time></p><p class="title is-6"><a class="link-muted" href="/2020/05/31/blog-theme-upgrade/">记Icarus博客主题升级</a></p><p class="is-uppercase"><a class="link-muted" href="/categories/%E9%BB%98%E8%AE%A4/">默认</a></p></div></article><article class="media"><a class="media-left" href="/2020/03/28/jvm-monitor-practice/"><p class="image is-64x64"><img class="thumbnail" src="/picture/2020/20200328001.jpg" alt="JVM及Java监控原理与实践"></p></a><div class="media-content size-small"><p><time datetime="2020-03-28T07:33:00.000Z">2020-03-28</time></p><p class="title is-6"><a class="link-muted" href="/2020/03/28/jvm-monitor-practice/">JVM及Java监控原理与实践</a></p><p class="is-uppercase"><a class="link-muted" href="/categories/%E5%AD%A6%E4%B9%A0/">学习</a> / <a class="link-muted" href="/categories/%E5%AD%A6%E4%B9%A0/java/">java</a></p></div></article></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">分类</h3><ul class="menu-list"><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/"><span class="level-start"><span class="level-item">学习</span></span><span class="level-end"><span class="level-item tag">37</span></span></a><ul class="mr-0"><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/docker/"><span class="level-start"><span class="level-item">docker</span></span><span class="level-end"><span class="level-item tag">3</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/elastic/"><span class="level-start"><span class="level-item">elastic</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/java/"><span class="level-start"><span class="level-item">java</span></span><span class="level-end"><span class="level-item tag">7</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/nginx/"><span class="level-start"><span class="level-item">nginx</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/python/"><span class="level-start"><span class="level-item">python</span></span><span class="level-end"><span class="level-item tag">10</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/spring/"><span class="level-start"><span class="level-item">spring</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85/"><span class="level-start"><span class="level-item">环境安装</span></span><span class="level-end"><span class="level-item tag">5</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/%E8%84%9A%E6%9C%AC%E5%91%BD%E4%BB%A4/"><span class="level-start"><span class="level-item">脚本命令</span></span><span class="level-end"><span class="level-item tag">5</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E5%AD%A6%E4%B9%A0/%E9%97%AE%E9%A2%98%E5%A4%84%E7%90%86/"><span class="level-start"><span class="level-item">问题处理</span></span><span class="level-end"><span class="level-item tag">4</span></span></a></li></ul></li><li><a class="level is-mobile is-marginless" href="/categories/%E7%9B%B8%E5%86%8C/"><span class="level-start"><span class="level-item">相册</span></span><span class="level-end"><span class="level-item tag">8</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/%E9%BB%98%E8%AE%A4/"><span class="level-start"><span class="level-item">默认</span></span><span class="level-end"><span class="level-item tag">10</span></span></a></li></ul></div></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">归档</h3><ul class="menu-list"><li><a class="level is-mobile is-marginless" href="/archives/2021/04/"><span class="level-start"><span class="level-item">四月 2021</span></span><span class="level-end"><span class="level-item tag">3</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/05/"><span class="level-start"><span class="level-item">五月 2020</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/03/"><span class="level-start"><span class="level-item">三月 2020</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2019/12/"><span class="level-start"><span class="level-item">十二月 2019</span></span><span class="level-end"><span class="level-item tag">3</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2019/11/"><span class="level-start"><span class="level-item">十一月 2019</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2019/10/"><span class="level-start"><span class="level-item">十月 2019</span></span><span class="level-end"><span class="level-item tag">6</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2019/09/"><span class="level-start"><span class="level-item">九月 2019</span></span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2019/07/"><span class="level-start"><span class="level-item">七月 2019</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2019/06/"><span class="level-start"><span class="level-item">六月 2019</span></span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2019/05/"><span class="level-start"><span class="level-item">五月 2019</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><a class="level is-mobile is-marginless" href="/archives/"><span class="level-start"><span class="level-item">查看全部&gt;&gt;</span></span></a></ul></div></div></div></div></div></div></section><footer class="footer"><div class="container"><div class="level"><div class="level-start"><a class="footer-logo is-block mb-2" href="/"><img class="footer-logo-img" src="/img/logo.png" alt="Trainoo的博客" height="28"></a><p class="size-small">  Powered by <a href="https://hexo.io/" target="_blank">Hexo</a> base on <a href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank">Icarus</a></p></div><div class="level-mid"><div class="field has-addons"><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Creative Commons" href="https://creativecommons.org/"><i class="fab fa-creative-commons"></i></a></p><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Attribution 4.0 International" href="https://creativecommons.org/licenses/by/4.0/"><i class="fab fa-creative-commons-by"></i></a></p><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Download on GitHub" href="https://github.com/ppoffice/hexo-theme-icarus"><i class="fab fa-github"></i></a></p></div></div><div class="level-end"><p class="size-small"><span><span id="statistic-times">loading...</span><script>function createTime(n){n=new Date(n);now.setTime(now.getTime()+250),days=(now-n)/1e3/60/60/24,dnum=Math.floor(days),hours=(now-n)/1e3/60/60-24*dnum,hnum=Math.floor(hours),1==String(hnum).length&&(hnum="0"+hnum),minutes=(now-n)/1e3/60-1440*dnum-60*hnum,mnum=Math.floor(minutes),1==String(mnum).length&&(mnum="0"+mnum),seconds=(now-n)/1e3-86400*dnum-3600*hnum-60*mnum,snum=Math.round(seconds),1==String(snum).length&&(snum="0"+snum),document.getElementById("statistic-times").innerHTML="♥ Security Run For <strong>"+dnum+"</strong> Days <strong>"+hnum+"</strong> Hours <strong>"+mnum+"</strong> Min <strong>"+snum+"</strong> Sec ♥"}var now=new Date;setInterval("createTime('12/14/2017 12:00:00')",250,"")</script><br></span></p><div class="size-small"><span>♥ Thanks For <strong><span id="busuanzi_value_site_uv">99+</span></strong> Visitors Come To My Site <a href="/memory" style="color:#4a4a4a">♥</a></span></div><p></p></div></div></div></footer><script src="/cdn/js/dist/jquery.min.js"></script><script src="/cdn/js/min/moment-with-locales.min.js"></script><script>moment.locale("zh-CN")</script><script>var IcarusThemeSettings={site:{url:"https://trainoo.gitee.io",external_link:{enable:!0,exclude:[]}},article:{highlight:{clipboard:!0,fold:"unfolded"}}}</script><script src="/cdn/js/dist/clipboard.min.js" defer></script><script src="/js/animation.js"></script><a id="back-to-top" title="回到顶端" href="javascript:;"><i class="fas fa-chevron-up"></i></a><script src="/js/back_to_top.js" defer></script><canvas class="fireworks" width="100%" height="100%" style="position:fixed;left:0;top:0;z-index:99999999;pointer-events:none"></canvas><script src="/js/anime.min.js" defer></script><script src="/js/fireworks.js" defer></script><script src="/cdn/js/dist/js/lightgallery.min.js" defer></script><script src="/cdn/js/dist/js/jquery.justifiedGallery.min.js" defer></script><script>window.addEventListener("load",()=>{"function"==typeof $.fn.lightGallery&&$(".article").lightGallery({selector:".gallery-item"}),"function"==typeof $.fn.justifiedGallery&&($(".justified-gallery > p > .gallery-item").length&&$(".justified-gallery > p > .gallery-item").unwrap(),$(".justified-gallery").justifiedGallery())})</script><script src="/js/main.js" defer></script><script src="/js/universe.js"></script><div class="searchbox"><div class="searchbox-container"><div class="searchbox-header"><div class="searchbox-input-container"><input class="searchbox-input" type="text" placeholder="想要查找什么..."></div><a class="searchbox-close" href="javascript:;">×</a></div><div class="searchbox-body"></div></div></div><script src="/js/insight.js" defer></script><script>document.addEventListener("DOMContentLoaded",function(){loadInsight({contentUrl:"/content.json"},{hint:"想要查找什么...",untitled:"(无标题)",posts:"文章",pages:"页面",categories:"分类",tags:"标签"})})</script></body></html>